package web.suzy.oj.config;

import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import web.suzy.oj.shiro.AccountRealm;
import web.suzy.oj.shiro.JwtFilter;
import web.suzy.oj.shiro.ShiroCacheManager;
import web.suzy.oj.shiro.ShiroConstant;
import web.suzy.oj.utils.RedisUtils;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * YangSuzy 软件工作室
 * 类名: ShiroConfig
 * 描述: Shiro配置类
 * 功能: 整合Shiro + Redis + JWT，实现会话共享，解决跨域身份验证
 *
 * @author YangSuzy
 * Date: 2022/11/14 15:21
 */
@Configuration
public class ShiroConfig {

    @Autowired
    private JwtFilter jwtFilter;

    @Autowired
    private RedisUtils redisUtils;

    @Value("${suzyoj.jwt.expire:86400}")
    private long expire;

    /**
     * 方法名: securityManager
     * 描述: Shiro配置核心 安全管理器
     *
     * @param accountRealm 自定义账户验证Realm
     * @return org.apache.shiro.web.mgt.DefaultWebSecurityManager
     * @date 2022/11/14 16:16
     * @auther YangSuzy
     **/
    @Bean
    public DefaultWebSecurityManager securityManager(AccountRealm accountRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(accountRealm);
        //设置缓存管理器
        ShiroCacheManager shiroCacheManager = new ShiroCacheManager();
        shiroCacheManager.setCacheLive(expire);
        shiroCacheManager.setCacheKeyPrefix(ShiroConstant.SHIRO_AUTHORIZATION_CACHE);
        shiroCacheManager.setRedisUtils(redisUtils);
        securityManager.setCacheManager(shiroCacheManager);
        //基于token进行身份验证和shiro自带的session冲突，关闭shiro自带的session进行无状态管理
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    /**
     * 方法名: shiroFilterChainDefinition
     * 描述: 指定过滤规则
     *
     * @return org.apache.shiro.spring.web.config.ShiroFilterChainDefinition
     * @date 2022/11/14 16:20
     * @auther YangSuzy
     **/
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        Map<String, String> filterMap = new LinkedHashMap<>();
        //放行Swagger相关访问，后期删除
        filterMap.put("/docs", "anon");
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/webjars/springfox-swagger-ui/**", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/v2/api-docs", "anon");
        //主要通过注解方式校验权限
        filterMap.put("/**", "jwt");
        chainDefinition.addPathDefinitions(filterMap);
        return chainDefinition;
    }

    /**
     * 方法名: shiroFilterFactoryBean
     * 描述: shiro拦截生成器
     *
     * @param securityManager            安全管理器
     * @param shiroFilterChainDefinition 过滤规则
     * @return org.apache.shiro.spring.web.ShiroFilterFactoryBean
     * @date 2022/11/14 16:22
     * @auther YangSuzy
     **/
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,
                                                         ShiroFilterChainDefinition shiroFilterChainDefinition) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        Map<String, Filter> filters = new HashMap<>();
        filters.put("jwt", jwtFilter);
        shiroFilter.setFilters(filters);
        Map<String, String> filterMap = shiroFilterChainDefinition.getFilterChainMap();
        shiroFilter.setFilterChainDefinitionMap(filterMap);
        return shiroFilter;
    }


    /**
     * 方法名: authorizationAttributeSourceAdvisor
     * 描述: 实现注解权限控制，如 @RequiresRoles和 @RequiresPermissions等
     *
     * @param securityManager 安全管理器
     * @return org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor
     * @date 2022/11/14 16:11
     * @auther YangSuzy
     **/
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


    /**
     * 方法名: getDefaultAdvisorAutoProxyCreator
     * 描述: 代理生成器，借助SpringAOP来扫描权限控制注解
     *
     * @return org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
     * @date 2022/11/14 16:14
     * @auther YangSuzy
     **/
    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
}
